package com.chapter17.demo8;

/**
 * 取消任务：
 * 在CancelableTask类中定义了一个boolean类型的变量cancel，在run
 * 方法中使用while循环来打印当前线程的名字，只要cancel为false，那么
 * 循环就将一直进行下去。在CancelableTask类中定义了一个cancelIt，将
 * 循环变量cancel设置为true。当外界调用CancelableTask对象的cancelIt方
 * 法后，while循环的条件为假，循环中止，任务退出。
 */
public class CancelableTask implements Runnable{

    /**
     * volatile关键
     * 字，这个关键字有何作用呢？我们知道，程序在运行时，代码和数据都
     * 是保存在内存中的，CPU在运算时，从内存中提取数据暂存到寄存器
     * 中，计算完成后，再将更新后的数据存回内存。现代CPU为了提高运算
     * 效率，增加了一级缓存和二级缓存，这同时也是为了存放临时数据。在
     * 一个并发程序中，多CPU可以同时运行多个线程，当一个CPU读取了内
     * 存地址中的某个数据，对其进行修改，但还未存回内存中时，在另一个
     * CPU上运行的线程访问了同一个内存地址的数据，此时看到的数据值就
     * 是不确定的。这也是为什么要对共享的资源进行同步访问的原因。有时
     * 候也没必要单独对一个变量的访问去做同步，而且还会存在一定隐患，
     * 这时就可以选择将该变量声明为volatile，这样编译器和JVM就知道这个
     * 变量可能会被另一个线程并发更新，从而保证volatile变量不会被存放到
     * CPU寄存器或它的缓存中，因此在其他线程读取该变量时总能得到最新
     * 写入的值。
     * 在访问volatile变量时不会执行加锁操作，因此也就不会出现线程阻
     * 塞的情况，可以把volatile变量看成是一种比sychronized更轻量级的同步
     * 机制。
     * 访问volatile变量比访问普通变量要稍慢一些，因为它需要插入一些
     * 额外的指令来保证线程安全，所以不要随便把变量声明为volatile，只有
     * 在需要的情况下才这么做。
     */
    private  volatile boolean cancel = false;
    @Override
    public void run() {
        while(!cancel){
            System.out.println(Thread.currentThread().getName());
        }
    }

    public void cancelIt(){
        cancel = true;
    }
}
